昨天討論了會員系統,我們今天我們進入實作環節。我們要選擇 JWT 來實作。
我們先來設計一下關於會員的API。在一般的工作場景下,會分前後端,可能比較小的公司或團隊就不會分。API 設計文件通常就是讓前後端溝通的一種文件。
因為通常前後端,會一起開發。但如果是在工作的話,身為前端的我們沒辦法等到後端開發完再開工吧!?不然這樣雖然前面沒事做很爽,但是如果有時程壓力的話(通常都會有)等到後端完成後就時間就會變得很趕。
所以在開發之前建議先和後端討論好後把API文件開好,然後前端就可以開始依據文件先開始實作,最後再串接再一起測試。
/auth/register
POST
{
"username": "john_doe",
"email": "john@example.com",
"password": "strongpassword",
"account": "john123"
}
{
"message": "註冊成功",
"user": {
"id": "12345",
"username": "john_doe",
"email": "john@example.com",
"account": "john123"
}
}
{
"error": "註冊失敗,該 email 已經被使用。"
}
/auth/login
POST
{
"email": "john@example.com",
"password": "strongpassword"
}
{
"message": "登入成功",
"access_token": "your_jwt_token"
}
{
"error": "帳號或密碼不正確。"
}
/users/:userId
GET
{
"id": "12345",
"username": "john_doe",
"email": "john@example.com",
"account": "john123",
"created_at": "2024-09-01T12:00:00Z"
}
{
"error": "授權失敗,請重新登入。"
}
/users/:userId
PUT
{
"username": "new_username",
"email": "newemail@example.com",
"account": "newaccount"
}
{
"message": "使用者資訊更新成功",
"user": {
"id": "12345",
"username": "new_username",
"email": "newemail@example.com",
"account": "newaccount"
}
}
{
"error": "更新失敗,email 已經被使用。"
}
首先我們需要先加上 JWT,先請 cur幫我們加上 JWT。
幫我加上 jwt 認證
[!Info] GPT 回應
根據你提供的需求,我將為你實作註冊、登入、取得使用者資訊和修改使用者資訊的 API。以下是相應的代碼實現:1. 更新
auth.service.ts
在
src/auth/auth.service.ts
中,添加註冊和登入的邏輯:import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { RegisterDto } from '../dto/register.dto'; import { User, UserDocument } from '../schemas/user.schema'; import { Model } from 'mongoose'; import { InjectModel } from '@nestjs/mongoose'; import { JwtPayload } from './jwt.payload'; @Injectable() export class AuthService { constructor( @InjectModel(User.name) private userModel: Model<UserDocument>, private jwtService: JwtService, ) {} async register(registerDto: RegisterDto): Promise<any> { const existingUser = await this.userModel.findOne({ email: registerDto.email }); if (existingUser) { throw new Error('註冊失敗,該 email 已經被使用。'); } const createdUser = new this.userModel(registerDto); await createdUser.save(); return { message: '註冊成功', user: { id: createdUser._id, username: createdUser.username, email: createdUser.email, account: createdUser.account, }, }; } async login(email: string, password: string): Promise<any> { const user = await this.userModel.findOne({ email }); if (!user || user.password !== password) { throw new Error('帳號或密碼不正確。'); } const payload: JwtPayload = { username: user.username }; const access_token = this.jwtService.sign(payload); return { message: '登入成功', access_token, }; } async validateUser(payload: JwtPayload): Promise<any> { return this.userModel.findOne({ username: payload.username }); } }
2. 更新
app.controller.ts
在
src/app.controller.ts
中,添加註冊和登入的路由:import { Controller, Post, Body, UseGuards, Get, Param, Put } from '@nestjs/common'; import { AppService } from './app.service'; import { RegisterDto } from './dto/register.dto'; import { AuthService } from './auth/auth.service'; import { AuthGuard } from '@nestjs/passport'; import { User } from './schemas/user.schema'; @Controller('auth') export class AppController { constructor( private readonly appService: AppService, private readonly authService: AuthService, ) {} @Post('register') async register(@Body() registerDto: RegisterDto): Promise<any> { return this.authService.register(registerDto); } @Post('login') async login(@Body() body: { email: string; password: string }): Promise<any> { return this.authService.login(body.email, body.password); } } @Controller('users') export class UserController { constructor(private readonly authService: AuthService) {} @UseGuards(AuthGuard('jwt')) @Get(':userId') async getUserInfo(@Param('userId') userId: string): Promise<User> { const user = await this.authService.validateUser({ username: userId }); if (!user) { throw new Error('授權失敗,請重新登入。'); } return user; } @UseGuards(AuthGuard('jwt')) @Put(':userId') async updateUserInfo(@Param('userId') userId: string, @Body() updateData: Partial<RegisterDto>): Promise<any> { const existingUser = await this.authService.validateUser({ username: userId }); if (!existingUser) { throw new Error('授權失敗,請重新登入。'); } const updatedUser = await this.authService.userModel.findByIdAndUpdate(userId, updateData, { new: true }); return { message: '使用者資訊更新成功', user: { id: updatedUser._id, username: updatedUser.username, email: updatedUser.email, account: updatedUser.account, }, }; } }
3. 更新
app.module.ts
確保在
src/app.module.ts
中導入UserController
:import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MongooseModule } from '@nestjs/mongoose'; import { User, UserSchema } from './schemas/user.schema'; import { AuthModule } from './auth/auth.module'; import { UserController } from './app.controller'; // 新增 @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:29017/ITHelp'), MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), AuthModule, ], controllers: [AppController, UserController], // 新增 providers: [AppService], }) export class AppModule {}
4. 錯誤處理
在實際應用中,建議使用 NestJS 的異常過濾器來處理錯誤,這樣可以更好地管理錯誤響應。
這樣就完成了註冊、登入、取得使用者資訊和修改使用者資訊的 API 實作。請根據需要進行測試和調整。
JWT 幫我加上去了,但其實打開終端機看還是會有些錯誤,可以通過反覆詢問AI修復。雖然是錯誤但不是太難的錯誤。向下面的錯誤,其實你可以通過再問AI去玩正,一直到終端機沒有錯誤。
我們剛剛寫了 API 文件,就是為了請 Cursor AI幫我們做出來。
(把文件貼上去) 幫我依照文件生成 API
[!Info] GPT 回應
根據你提供的需求,我將為你實作註冊、登入、取得使用者資訊和修改使用者資訊的 API。以下是相應的代碼實現:1. 更新
auth.service.ts
在
src/auth/auth.service.ts
中,添加註冊和登入的邏輯:import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { RegisterDto } from '../dto/register.dto'; import { User, UserDocument } from '../schemas/user.schema'; import { Model } from 'mongoose'; import { InjectModel } from '@nestjs/mongoose'; import { JwtPayload } from './jwt.payload'; @Injectable() export class AuthService { constructor( @InjectModel(User.name) private userModel: Model<UserDocument>, private jwtService: JwtService, ) {} async register(registerDto: RegisterDto): Promise<any> { const existingUser = await this.userModel.findOne({ email: registerDto.email }); if (existingUser) { throw new Error('註冊失敗,該 email 已經被使用。'); } const createdUser = new this.userModel(registerDto); await createdUser.save(); return { message: '註冊成功', user: { id: createdUser._id, username: createdUser.username, email: createdUser.email, account: createdUser.account, }, }; } async login(email: string, password: string): Promise<any> { const user = await this.userModel.findOne({ email }); if (!user || user.password !== password) { throw new Error('帳號或密碼不正確。'); } const payload: JwtPayload = { username: user.username }; const access_token = this.jwtService.sign(payload); return { message: '登入成功', access_token, }; } async validateUser(payload: JwtPayload): Promise<any> { return this.userModel.findOne({ username: payload.username }); } }
2. 更新
app.controller.ts
在
src/app.controller.ts
中,添加註冊和登入的路由:import { Controller, Post, Body, UseGuards, Get, Param, Put } from '@nestjs/common'; import { AppService } from './app.service'; import { RegisterDto } from './dto/register.dto'; import { AuthService } from './auth/auth.service'; import { AuthGuard } from '@nestjs/passport'; import { User } from './schemas/user.schema'; @Controller('auth') export class AppController { constructor( private readonly appService: AppService, private readonly authService: AuthService, ) {} @Post('register') async register(@Body() registerDto: RegisterDto): Promise<any> { return this.authService.register(registerDto); } @Post('login') async login(@Body() body: { email: string; password: string }): Promise<any> { return this.authService.login(body.email, body.password); } } @Controller('users') export class UserController { constructor(private readonly authService: AuthService) {} @UseGuards(AuthGuard('jwt')) @Get(':userId') async getUserInfo(@Param('userId') userId: string): Promise<User> { const user = await this.authService.validateUser({ username: userId }); if (!user) { throw new Error('授權失敗,請重新登入。'); } return user; } @UseGuards(AuthGuard('jwt')) @Put(':userId') async updateUserInfo(@Param('userId') userId: string, @Body() updateData: Partial<RegisterDto>): Promise<any> { const existingUser = await this.authService.validateUser({ username: userId }); if (!existingUser) { throw new Error('授權失敗,請重新登入。'); } const updatedUser = await this.authService.userModel.findByIdAndUpdate(userId, updateData, { new: true }); return { message: '使用者資訊更新成功', user: { id: updatedUser._id, username: updatedUser.username, email: updatedUser.email, account: updatedUser.account, }, }; } }
3. 更新
app.module.ts
確保在
src/app.module.ts
中導入UserController
:import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MongooseModule } from '@nestjs/mongoose'; import { User, UserSchema } from './schemas/user.schema'; import { AuthModule } from './auth/auth.module'; import { UserController } from './app.controller'; // 新增 @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:29017/ITHelp'), MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), AuthModule, ], controllers: [AppController, UserController], // 新增 providers: [AppService], }) export class AppModule {}
4. 錯誤處理
在實際應用中,建議使用 NestJS 的異常過濾器來處理錯誤,這樣可以更好地管理錯誤響應。
這樣就完成了註冊、登入、取得使用者資訊和修改使用者資訊的 API 實作。請根據需要進行測試和調整。
按下套用讓Cursor 幫你修改程式碼,一樣會有一些錯誤,可以按下面 AI FIx in Chat 來回修改到沒有錯誤為止。
全部修完後還會出現這個問題,但不用擔心,一樣可以丟到AI修復。
我覺得套用玩來回修復的過程會有一點折磨,因為其實有些如果你知道的話自己修改會比較快。AI有時候會和你鬼打牆。如果全部都靠AI的話一樣會有一些問題。但也不是不能完成任務,只是需要比較多耐心。
總之,AI 幫我們完成程式碼了。明天再來驗證一下他寫的對不對,有沒有照文件寫。